//
// Created by 86183 on 2022/12/6.
//

#include "stu.h"

extern int CurrentStudent;
extern int CurrentAdmin;

void WelcomeS()
{
    printf("*****************************************\n");
    printf("*\t   欢迎使用学生管理系统  \t*\n");
    printf("*****************************************\n");
    printf("*\t\t请选择功能列表\t\t*\n");
    printf("*\t\t1.录入学生信息\t\t*\n");
    printf("*\t\t2.打印学生信息\t\t*\n");
    printf("*\t\t3.保存学生信息\t\t*\n");
    printf("*\t\t4.读取学生信息\t\t*\n");
    printf("*\t\t5.查找学生信息\t\t*\n");
    printf("*\t\t6.修改学生信息\t\t*\n");
    printf("*\t\t7.删除学生信息\t\t*\n");
    printf("*\t\t8.学生成绩排序\t\t*\n");
    printf("*\t\t9.删除所有信息(慎用)  *\n");
    printf("*\t\t0.退出系统\t\t    *\n");
    printf("*****************************************\n");
}

void WelcomeA()
{
    printf("*****************************************\n");
    printf("*\t   欢迎使用学生管理系统  \t*\n");
    printf("*****************************************\n");
    printf("*\t\t请选择功能列表\t\t*\n");
    printf("*\t\t1.登录\t\t*\n");
    printf("*\t\t2.注册\t\t*\n");
    printf("*\t\t3.忘记密码\t*\n");
    printf("*\t\t4.退出\t\t*\n");
    printf("*****************************************\n");
}

NodeS* read_txtS(FILE* fp)
{
    NodeS* stu = (NodeS*) malloc(sizeof(NodeS));
    assert(stu != NULL);//验证 malloc 申请是否成功
    int ret = fscanf(fp, "%s %s %d %s %d\n",
                     stu -> data.id,
                     stu -> data.name,
                     &stu -> data.age,
                     stu -> data.gender,
                     &stu -> data.grade);

    if (ret == EOF)
    {
        free(stu);//释放空间
        stu = NULL;
        fclose(fp);
    }
    return stu;
}

NodeA* read_txtA(FILE* fp)
{
    NodeA* adm = (NodeA*) malloc(sizeof(NodeA));
    assert(adm != NULL);//验证 malloc 申请是否成功
    int ret = fscanf(fp, "%s %s %s %s\n",
                     adm -> data.username,
                     adm -> data.password,
                     adm -> data.id,
                     adm -> data.phoneNumber);

    if (ret == EOF)
    {
        free(adm);//释放空间
        adm = NULL;
        fclose(fp);
    }
    return adm;
}

void init_listS(NodeS** pS)
{
    *pS = (NodeS*) malloc(sizeof(NodeS));//头节点空间
    (*pS) -> next = NULL;// Head 指向的 next(第一个节点)置空

    FILE* fp;//读取文件
    fp = fopen("C:\\Users\\86183\\Desktop\\c_test\\test\\Student_management_system\\Stu.txt", "r");

    NodeS* stu = NULL;
    NodeS* tmp = NULL;
    int count = 0;
    while ((stu = read_txtS(fp)) != NULL) //读取文件
    {
        if (count == 0) //头插
        {
            stu -> next = (*pS) -> next;
            (*pS) -> next = stu;
            tmp = stu;
        }
        else //尾插
        {
            stu -> next = tmp -> next;
            tmp -> next = stu;
            tmp = stu;
        }
        count ++;
    }
    CurrentStudent = count;
    printf("读取完成\n");
}

void init_listA(NodeA** pA)
{
    *pA = (NodeA*) malloc(sizeof(NodeA));//头节点空间
    (*pA) -> next = NULL;// Head 指向的 next(第一个节点)置空

    FILE* fp;//读取文件
    fp = fopen("C:\\Users\\86183\\Desktop\\c_test\\test\\Student_management_system\\Adm.txt", "r");

    NodeA* adm = NULL;
    NodeA* tmp = NULL;
    int count = 0;
    while ((adm = read_txtA(fp)) != NULL) //读取文件
    {
        if (count == 0) //头插
        {
            adm -> next = (*pA) -> next;
            (*pA) -> next = adm;
            tmp = adm;
        }
        else //尾插
        {
            adm -> next = tmp -> next;
            tmp -> next = adm;
            tmp = adm;
        }
        count ++;
    }
    CurrentAdmin = count;
    printf("读取完成\n");
}

void output_one_student(NodeS* S)
{
    printf("%s\t", S -> data.id);
    printf("%s  \t", S -> data.name);
    printf("%d\t", S -> data.age);
    printf("%s\t", S -> data.gender);
    printf("%d\n", S -> data.grade);
}

void output_all_students(NodeS* S)
{
    printf("打印所有学生\n");
    if (S -> next == NULL)
    {
        printf("没有学生\n");
    }
    while (S -> next != NULL)
    {
        S = S -> next;
        output_one_student(S);
    }
    printf("目前共有 %d 个学生\n", CurrentStudent);
}

int is_username_contains(NodeA* A, const char username[])
{
    int index = -1;
    int count = 0;
    while (A -> next != NULL)
    {
        count++;
        A = A -> next;
        if (strcmp(username, A -> data.username) == 0)
        {
            index = count;
        }
    }
    return index;
}

bool is_username_legal(NodeA* A, char username[])
{
    int count = 0;//用户名中的字母数
    unsigned long len = strlen(username);
    if (len < 3)
    {
        printf("用户名过短，请重新输入\n");
        return false;
    }
    else if (len > 15)
    {
        printf("用户名过长，请重新输入\n");
        return false;
    }
    for (int i = 0; i < len; i++)
    {
        if ((username[i] > 'Z' && username[i] < 'a') || username[i] < '0' || (username[i] > '9' && username[i] < 'A') || username[i] > 'z' )
        //保证用户名格式是字母大小写和数字
        {
            printf("用户名输入格式错误，请重新输入\n");
            return false;
        }
        else if ((username[i] > 'A' && username[i] < 'Z') || (username[i] > 'a' && username[i] < 'z'))
        {
            count ++;
        }
    }
    if (count == 0)
    {
        printf("用户名中缺少字母，请重新输入\n");
        return false;
    }
    int index = is_username_contains(A, username);
    if (index >= 0)
    {
        printf("用户名已存在，请重新输入\n");
        return false;
    }
    return true;
}

bool is_id_legal(char id[])
{
    unsigned long len = strlen(id);
    if (len != 18) //判断长度为 18
    {
        printf("输入错误，请重新输入\n");
        return false;
    }
    if (id[0] == '0') //判断第一位不是 0
    {
        printf("输入错误，请重新输入\n");
        return false;
    }
    for (int i = 0; i < len; i++)
    {
        bool flag = id[i] < '0' || id[i] > '9';//判断每一位是不是数字
        if (i < len - 1)
        {
            if (flag)
            {
                printf("输入错误，请重新输入\n");
                return false;
            }
        }
        else
        {
            if ((flag) && id[i] != 'X' && id[i] != 'x') //最后一位可以是 X
            {
                printf("输入错误，请重新输入\n");
                return false;
            }
        }
    }
    return true;
}

bool is_phoneNumber_legal(char phoneNumber[])
{
    unsigned long len = strlen(phoneNumber);
    if (len != 11) //判断长度是 11 位
    {
        printf("输入错误，请重新输入\n");
        return false;
    }
    if (phoneNumber[0] == '0') //判断第一位不是 0
    {
        printf("输入错误，请重新输入\n");
        return false;
    }
    for (int i = 0; i < len; i++)
    {
        if (phoneNumber[i] > '9' || phoneNumber[i] < '0') //判断每一位是数字
        {
            printf("输入错误，请重新输入\n");
            return false;
        }
    }
    return true;
}

void Register(NodeA* A)
{
    printf("注册\n");

    char username[MAX_NAME_LEN];
    char password[MAX_PASSWORD_LEN];
    char re_password[MAX_PASSWORD_LEN];
    char id[MAX_ID_LEN];
    char phoneNumber[MAX_PHONENUMBER_LEN];

    // 1.用户名
    while (true)
    {
        printf("请输入用户名:>");
        scanf("%s", username);
        bool flag = is_username_legal(A, username);//判断用户名是否合法
        if (flag)
        {
            break;
        }
    }

    // 2.密码
    while (true)
    {
        printf("请输入密码:>");
        scanf("%s", password);
        printf("请再次输入密码:>");
        scanf("%s", re_password);
        if (strcmp(password, re_password) == 0)
        {
            break;
        }
        else
        {
            printf("两次输入密码不一致，请重新输入\n");
        }
    }

    // 3.id
    while (true)
    {
        printf("请输入身份证号码:>");
        scanf("%s", id);
        bool flag = is_id_legal(id);//判断合法性
        if (flag)
        {
            break;
        }
    }

    // 4.手机号
    while (true)
    {
        printf("请输入手机号:>");
        scanf("%s", phoneNumber);
        bool flag = is_phoneNumber_legal(phoneNumber);
        if (flag)
        {
            break;
        }
    }

    //插入链表(头插)
    NodeA* adm = (NodeA*) malloc(sizeof(NodeA));
    strcpy(adm -> data.username, username);
    strcpy(adm -> data.password, password);
    strcpy(adm -> data.id, id);
    strcpy(adm -> data.phoneNumber, phoneNumber);

    adm -> next = A -> next;
    A -> next = adm;

    CurrentAdmin++;
    printf("注册成功\n");
}

void forget_password(NodeA* A)
{
    printf("忘记密码\n");

rewrite:
    while (true)
    {
        printf("请输入您的用户名:>");
        char username[MAX_NAME_LEN];
        scanf("%s", username);

        int index = is_username_contains(A, username);
        if (index < 0)
        {
            printf("用户未注册\n");
            while (true)
            {
                printf("按 A 重新输入用户名，按 B 跳转到注册界面，按 C 退出:>");
                char input;
                scanf("%c", &input);

                switch (input)
                {
                    case 'A':
                        goto rewrite;
                    case 'B':
                        Register(A);
                        return;
                    case 'C':
                        return;
                    default:
                        printf("没有这个选项\n");
                        break;
                }
            }
        }
        else
        {
            for (int i = 0; i < index; i++) //找到对应的用户信息
            {
                A = A -> next;
            }

            printf("请输入身份证号码:>");
            char id[MAX_ID_LEN];
            scanf("%s", id);

            printf("请输入手机号码:>");
            char phoneNumber[MAX_PHONENUMBER_LEN];
            scanf("%s", phoneNumber);

            if ((strcmp(id, A -> data.id) == 0) && (strcmp(phoneNumber, A -> data.phoneNumber) == 0))
            {
                printf("请输入修改后的密码:>");
                char password[MAX_PASSWORD_LEN];
                scanf("%s", password);
                strcpy(A -> data.password, password);
                printf("修改成功\n");
                return;
            }
            else
            {
                printf("账号信息不匹配，修改失败\n");
            }
            break;
        }
    }
}

char* get_verification_code(char code[])
{
    srand((unsigned) time(NULL));

    char arr[52];
    int num[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    for (int i = 0; i < 52; i++)
    {
        if (i < 26)
        {
            arr[i] = (char) (65 + i);
        }
        else
        {
            arr[i] = (char) (97 + i - 26);
        }
    }

    for (int i = 0; i < 5; i++)
    {
        if (i < 4)
        {
            int cIndex = rand() % 52;
            code[i] = arr[cIndex];
        }
        else
        {
            int nIndex = rand() % 10;
            code[4] = num[nIndex] + '0';
        }
    }
    return code;
}

bool sign_in(NodeA* A)
{
    NodeA* tmp = A;
    printf("登录\n");

    while (true)
    {
        printf("请输入用户名(按 Q 跳转到注册界面):>");
        char username[MAX_NAME_LEN];
        scanf("%s", username);

        if (username[0] == 'Q' || username[0] == 'q')
        {
            Register(A);
            return false;
        }
        else
        {
            int index = is_username_contains(A, username);
            if (index < 0)
            {
                printf("用户名不存在，请重新输入\n");
            }
            else
            {
                for (int i = 0; i < index; i++) //找到对应的用户信息
                {
                    A = A -> next;
                }

                for (int i = 0; ; )
                {
                    printf("请输入密码(按 Q 跳转到忘记密码):>");
                    char password[MAX_PASSWORD_LEN];
                    scanf("%s", password);

                    if (password[0] == 'Q' || password[0] == 'q')
                    {
                        forget_password(tmp);
                        return false;
                    }

                    char realCode[VERIFICATION_LEN + 1];
                    get_verification_code(realCode);//获取验证码
                    realCode[5] = '\0';//停止

                    printf("验证码是:%s\n", realCode);
                    printf("请输入验证码(区分大小写):>");
                    char tmpCode[VERIFICATION_LEN + 1];
                    scanf("%s", tmpCode);
                    tmpCode[5] = '\0';

                    if (strcmp(realCode, tmpCode) == 0)
                    {
                        if (strcmp(password, A -> data.password) == 0)
                        {
                            printf("登陆成功\n");
                            return true;
                        }
                        else
                        {
                            if (i != 2) // 3 次机会
                            {
                                printf("密码错误，请重新输入，您还剩下 %d 次机会\n", 2 - i);
                                i ++;
                            }
                            else
                            {
                                printf("错误次数过多，您的账户已被冻结，请联系管理员\n");
                                return false;
                            }
                        }
                    }
                    else
                    {
                        printf("验证码错误，请重新输入\n");
                    }
                }
            }
        }
    }
}

StudentInfo* create_student()
{
    StudentInfo* stu = (StudentInfo*) malloc(sizeof(StudentInfo));
    printf("请输入学生的 id，姓名，年龄，性别，成绩\n");
    printf("请输入学生 id:>");
    scanf("%s", stu -> id);
    printf("请输入学生姓名:>");
    scanf("%s", stu -> name);
    printf("请输入学生年龄:>");
    scanf("%d", &stu -> age);
    printf("请输入学生性别:>");
    scanf("%s", stu -> gender);
    printf("请输入学生成绩:>");
    scanf("%d", &stu -> grade);

    return stu;
}

bool insert_student(NodeS* S, StudentInfo stu, int choice)
{
    printf("插入学生信息\n");
    NodeS* newStu = (NodeS*) malloc(sizeof(NodeS));
    newStu -> data = stu;

    switch (choice)
    {
        case 1:
            newStu -> next = S -> next;
            S -> next = newStu;
            CurrentStudent++;
            printf("添加成功\n");
            return true;
        case 0:
            while (S -> next != NULL)
            {
                S = S -> next;
            }
            newStu -> next = S -> next;
            S -> next = newStu;
            CurrentStudent++;
            printf("添加成功\n");
            return true;
        default:
            for (int i = 0; i < choice - 1; i++)
            {
                S = S -> next;
                if (S == NULL)
                {
                    printf("添加失败，节点不存在\n");
                    return false;
                }
            }
            newStu -> next = S -> next;
            S -> next = newStu;
            CurrentStudent++;
            printf("添加成功\n");
            return true;
    }
}

int save_to_file(NodeS* S)
{
    printf("保存学生信息\n");

    FILE* fp;
    fp = fopen("C:\\Users\\86183\\Desktop\\c_test\\test\\Student_management_system\\Stu.txt", "w");

    if (S == NULL || S -> next == NULL)
    {
        fclose(fp);
        printf("保存成功\n");
        return 0;
    }

    while (S -> next != NULL)
    {
        fprintf(fp, "%s\t", S -> next -> data.id);
        fprintf(fp, "%s  \t", S -> next -> data.name);
        fprintf(fp, "%d\t", S -> next -> data.age);
        fprintf(fp, "%s\t", S -> next -> data.gender);
        fprintf(fp, "%d\n", S -> next -> data.grade);
        S = S -> next;
    }

    fclose(fp);
    printf("保存成功\n");
    return CurrentStudent;
}

void destroy_list(NodeS** pS)
{
    if ((*pS) == NULL)
    {
        printf("链表已销毁，请勿重复销毁\n");
    }
    else
    {
        while ((*pS) -> next != NULL)
        {
            NodeS* tmp = (*pS) -> next;
            (*pS) -> next = tmp -> next;
            free(tmp);
            tmp = NULL;
        }
        free(*pS); /* 释放头节点 */
        *pS = NULL;
        CurrentStudent = 0;
        printf("销毁成功\n");
    }
}

NodeS* search_student(NodeS *S, char* student_id)
{
    printf("查询学生信息\n");

    if (S -> next == NULL)
    {
        printf("无法查询，链表中没有学生\n");
        return NULL;
    }
    while (S -> next != NULL)
    {
        S = S -> next;
        if (!strcmp(S -> data.id, student_id))
        {
            printf("查询成功\n");
            output_one_student(S);
            return S;
        }
    }
    printf("查询失败，未能找到此学生\n");
    return NULL;
}

bool delete_student(NodeS* S, char* student_id)
{
    printf("删除学生信息\n");
    /* 注意先判断链表中有没有文件 */
    if (S -> next == NULL)
    {
        printf("删除失败，链表中没有学生\n");
        return false;
    }
    while (strcmp(student_id, S -> next -> data.id) != 0)
    {
        S = S -> next;
        if (S -> next == NULL)
        {
            printf("删除失败\n");
            return false;
        }
    }

    NodeS* tmp = S -> next;
    S -> next = S -> next -> next;
    free(tmp);
    tmp = NULL;
    CurrentStudent--;
    printf("删除成功\n");
    return true;
}

bool change_student(NodeS *S, char* student_id, StudentInfo new_info)
{
    printf("修改某个学生的信息\n");
    NodeS* stu = search_student(S, student_id);
    if (stu == NULL)
    {
        printf("修改失败，没有找到此学生\n");
        return false;
    }
    else
    {
        stu -> data = new_info;
        printf("已经将 id 为 %s 的学生修改为:\n", student_id);
        search_student(S, new_info.id);
        return true;
    }
}

void bubble_sort(NodeS *S)
{
    printf("对学生按成绩进行排序\n");
    if (CurrentStudent == 1 || !CurrentStudent)
        return;
    int i;
    for (i = 0; i < CurrentStudent; i++) // i 趟冒泡排序
    {
        for (NodeS* pre = S; pre -> next -> next != NULL; pre = pre -> next)
        {
            NodeS* now = pre -> next;
            NodeS* cur = now -> next;
            if (now -> data.grade > cur -> data.grade)
            {
                pre -> next = cur;
                now -> next = cur -> next;
                cur -> next = now;
            }
        }
    }

    double sum = 0;
    NodeS* tmp = S;
    for (i = 0; i < CurrentStudent; i++)
    {
        tmp = tmp -> next;
        sum += tmp -> data.grade;
    }
    double avg = sum / CurrentStudent;

    NodeS* tmp0 = S;
    int numDown = 0;
    int numUp = 0;
    for (i = 0; i < CurrentStudent; i++)
    {
        tmp0 = tmp0 -> next;
        if (tmp0 -> data.grade < avg)
        {
            numDown++;
        }
        else
        {
            numUp++;
        }
    }

    printf("学生的成绩平均分是:%.2lf\n", avg);
    printf("有 %d 个学生小于平均分\n", numDown);
    printf("有 %d 个学生大于等于平均分\n", numUp);
}

void destroy_list_and_file(NodeS** pS)
{
    printf("(慎用)删除所有内容\n");
    destroy_list(pS);

    remove("C:\\Users\\86183\\Desktop\\c_test\\test\\Student_management_system\\Stu.txt");
}